package com.tegistuff.webos.run.debugger;

import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.SimpleColoredComponent;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.xdebugger.XDebuggerUtil;
import com.intellij.xdebugger.XSourcePosition;
import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
import com.intellij.xdebugger.frame.XCompositeNode;
import com.intellij.xdebugger.frame.XStackFrame;
import com.intellij.xdebugger.frame.XValueChildrenList;
import com.intellij.xdebugger.ui.DebuggerIcons;
import com.tegistuff.webos.run.debugger.breakpoints.WebOSBreakpointWrapper;
import com.tegistuff.webos.run.debugger.infrastructure.WebOSVar;
import com.tegistuff.webos.util.WebOSFileMapper;
import org.jetbrains.annotations.NotNull;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.regex.Pattern;

/**
 * WebOSStackFrame.java
 *
 * Copyright (C) 2011-2012 Timo Tegtmeier.
 * All rights reserved.
 */
public class WebOSStackFrame extends XStackFrame {

    private WebOSDebugProcess myDebugProcess;
    private XSourcePosition mySourcePosition;
    private WebOSBreakpointWrapper myBreakpointWrapper;
    private XValueChildrenList myValues;
    
    private String myFileName;
    private String myFunction;
    private int myLineNumber;
    private int myFrameNumber;
    
    private static Pattern funcPattern = Pattern.compile("#\\d+\\s#([^(]*).*");
    private static Pattern filePattern = Pattern.compile(".*file://(/[^\\s]*)\\sline.*");

    public WebOSStackFrame(WebOSDebugProcess debugProcess, JSONObject frame) throws JSONException {
        myDebugProcess = debugProcess;

        // Collect basic information.
        myFrameNumber = frame.getInt("index");
        String text = frame.getString("text").replaceAll("\n", "");
        myFunction = funcPattern.matcher(text).replaceAll("$1");
        myFileName = filePattern.matcher(text).replaceAll("$1");
        int sourceLine = frame.getInt("line");
        myLineNumber = sourceLine + 1;

        // Collect information about file and possible breakpoint.
        VirtualFile file = WebOSFileMapper.MapToLocalFile(myDebugProcess.getRunConfiguration(), "file://" + myFileName);
        if(file != null) {
            mySourcePosition = XDebuggerUtil.getInstance().createPosition(file, sourceLine);
            myBreakpointWrapper = myDebugProcess.getLineBreakpointHandler().findBreakpointWrapper(myFileName, sourceLine);
        }

        // Build variables list.
        myValues = new XValueChildrenList();
        addVariables(frame.getJSONArray("locals"), myDebugProcess);
        addVariables(frame.getJSONArray("arguments"), myDebugProcess);
    }

    @Override
    public Object getEqualityObject() {
        return 0;
    }

    @Override
    public void computeChildren(@NotNull final XCompositeNode node) {
        try {
            node.addChildren(myValues, true);
        } catch (Exception e) {
            super.computeChildren(node);
        }
    }

    @Override
    public XSourcePosition getSourcePosition() {
        return mySourcePosition;
    }

    @Override
    public void customizePresentation(final SimpleColoredComponent component) {
        final XSourcePosition position = getSourcePosition();
        component.append(String.format("%s() ", myFunction),
                position != null ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES);
        component.append(String.format("(%s : %d)", myFileName, myLineNumber),
                SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES);
        component.setIcon(DebuggerIcons.STACK_FRAME_ICON);
    }

    @Override
    public XDebuggerEvaluator getEvaluator() {
        return new WebOSDebuggerEvaluator(myDebugProcess.getDebuggerProxy());
    }

    public WebOSBreakpointWrapper getBreakpointWrapper() {
        return myBreakpointWrapper;
    }

    private void addVariables(JSONArray values, WebOSDebugProcess debugProcess) throws JSONException {
        for(int i = 0; i < values.length(); i++) {
            JSONObject var = values.getJSONObject(i);
            if(!var.has("name"))
                continue;
            String name = var.getString("name");
            if(name.startsWith("."))
                continue;
            myValues.add(name, new WebOSVar(debugProcess, var.getJSONObject("value")));
        }
    }

    public final int getFrameNumber() {
        return myFrameNumber;
    }
}
